home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Game Programming Gurus / Tricks of the Windows Game Programming Gurus (SAMS)(2000).iso / Articles / LinkingUpDirectPlay / dptools.cpp < prev    next >
C/C++ Source or Header  |  1999-06-01  |  29KB  |  1,042 lines

  1. /*
  2. Semion S. Bezrukov 5-31-99
  3. e-mail: deltree@rocketmail.com
  4. This file is a compilation of Direct Play routines for the management
  5. and setup of DirectPlay object and player. The majority of this code comes
  6. from 'Inside Direct X' by Bradley Bargen and Peter Donnelly. There, that's
  7. all the legal stuff.
  8. To get this to work with your program, simply include 'dptools.h' in
  9. your main .h file and initialize DirectPlay like so: 
  10.  
  11.   InitializeDirectPlay(hinstance);
  12.  
  13. where hinstance is the instance of your application.
  14. To deinitialize DirectPlay, simply use:
  15.  
  16.     UninitializeDirectPlay();
  17.  
  18. just before you quit the application. You must have dplay.lib and 
  19. dplayx.lib specified in your library compile path or you'll get a ton
  20. of link errors.
  21. To see how to send and receive data simply look to the SendFireMessage()
  22. and EvaluateGameMessage().
  23. SendFireMessage() simply fills the FIREMSG struct and then sends it using
  24. another general function.
  25. EvaluateGameMessage(), casts the received struct to a general struct
  26. to figure out the exact type and then recasts it to the specific struct
  27. so that the data can be extracted.
  28. Good luck,
  29.     SIM.
  30. */
  31.  
  32.  
  33. #define WIN32_LEAN_AND_MEAN
  34. #define IDIRECTPLAY2_OR_GREATER
  35. #define INITGUID
  36.  
  37.  
  38. #include <windows.h>
  39. #include <windowsx.h>
  40. #include <stdio.h>
  41. #include <objbase.h>    // GUID functions
  42.  
  43.  
  44. #include "dplay.h"
  45. #include "dplobby.h"
  46. #include "dptools.h"
  47. #include "resource.h"
  48. #include "dpex.h"
  49.  
  50.  
  51.  
  52. int receive_count;            //a global variable that holds the recieved
  53.                             //data. When the main program asks for it, a
  54.                             //function simply returns it. I chose this
  55.                             //approach for it's ease.
  56.  
  57.  
  58. typedef struct
  59. {
  60.     GUID    guidSP;
  61.     LPVOID     lpConnection;
  62.     DWORD    dwConnectionSize;
  63. }CONNECTIONINFO;
  64.  
  65. typedef CONNECTIONINFO* LPCONNECTIONINFO;
  66.  
  67.  
  68. GUID ZCAR_GUID = {
  69.     0x949a21e2,
  70.     0x6179,
  71.     0x11cf,
  72.     {0x95, 0x4f, 0x00, 0xaa, 0x00, 0x6c, 0x26, 0x58}
  73. };
  74.  
  75.  
  76. #define TIMER_ID        1
  77. #define TIMER_RATE      2000            // milliseconds
  78.  
  79.  
  80. LPDIRECTPLAY3       lpDP                = NULL;
  81. LPDIRECTPLAYLOBBY2    lpDPLobby2            = NULL;
  82. DPSESSIONDESC2      dpDesc;
  83. LPDPSESSIONDESC2    lpdpDesc            = NULL;
  84. DPCAPS              dpCaps;
  85. HANDLE              hPlayerEvent        = NULL;
  86. HANDLE              hKillEvent            = NULL;
  87. HANDLE              hReceiveThread        = NULL;
  88. DWORD               idReceiveThread        = 0;
  89. LPVOID              lpReceiveBuffer        = NULL;
  90. DWORD               dwReceiveBufferSize = 0;
  91. bool                bEnumerating        = FALSE;
  92. bool                bUserCancel            = TRUE;
  93.  
  94. HOSTMSG                MsgHost;
  95. SYNCMSG                MsgSync;
  96. FIREMSG                MsgFire;
  97. CONTROLMSG            MsgControl;
  98.  
  99. BOOL        g_bHost    = FALSE;
  100. char        g_szPlayerName[31];        // our name
  101. DPID        g_dpPlayerID;            // our id
  102.  
  103. HANDLE                  g_hInstance;
  104. HWND                    g_hwnd;
  105.  
  106.  
  107.  
  108.  
  109.  
  110. void InitMessageBuffers( void )
  111. {
  112.     MsgHost.byType        = MSG_HOST;
  113.     MsgSync.byType        = MSG_SYNC;
  114.     MsgFire.byType        = MSG_FIRE;
  115.     MsgControl.byType    = MSG_CONTROL;
  116. }
  117.  
  118.  
  119. BOOL FAR PASCAL EnumPlayer( DPID pidID,
  120.                             DWORD dwPlayerType, LPCDPNAME lpName, 
  121.                             DWORD dwFlags, LPVOID lpContext)
  122. {
  123.     HWND hWnd = ( HWND ) lpContext;
  124.  
  125.     SendMessage( hWnd, LB_ADDSTRING, 0, 
  126.                     ( LPARAM ) lpName->lpszShortNameA );
  127.  
  128.     return( TRUE );
  129. }
  130.  
  131.  
  132. BOOL WINAPI EnumConnection( LPCGUID lpguidSP,
  133.                             LPVOID lpConnection, DWORD dwSize,
  134.                             LPDPNAME lpName, DWORD dwFlags, 
  135.                             LPVOID lpContext )
  136. {
  137.     LONG                iIndex;
  138.     HWND hWnd            = ( HWND ) lpContext;
  139.     LPVOID                lpOurConnection = NULL;
  140.     LPCONNECTIONINFO    lpConnectionInfo = NULL;
  141.     LPDIRECTPLAY3        lpDPTemp;
  142.  
  143.     // Check to see if a connection can be initialized
  144.     if FAILED( CoCreateInstance( CLSID_DirectPlay,
  145.                 NULL, CLSCTX_ALL, IID_IDirectPlay3A,
  146.                 ( LPVOID* ) &lpDPTemp ) )
  147.     {
  148.         return( FALSE );
  149.     }
  150.  
  151.     if FAILED( lpDPTemp->InitializeConnection( lpConnection, 0 ) )
  152.     {
  153.         lpDPTemp->Release();
  154.         return( TRUE );
  155.     }
  156.     lpDPTemp->Release();
  157.  
  158.     // If it was initialized, add it to the list box
  159.     iIndex = SendMessage( hWnd, CB_ADDSTRING, 0, 
  160.                             (LPARAM) lpName->lpszShortNameA );
  161.  
  162.     // If it got added to the list box, create a copy of the connection
  163.     // info and store a pointer to it in the list box.
  164.     if ( iIndex != LB_ERR )
  165.     {
  166.         lpConnectionInfo = 
  167.             (LPCONNECTIONINFO)malloc( sizeof( CONNECTIONINFO ) );
  168.  
  169.         memcpy( &lpConnectionInfo->guidSP, lpguidSP, sizeof( GUID ) );
  170.  
  171.         lpConnectionInfo->lpConnection = malloc( dwSize );
  172.         memcpy( lpConnectionInfo->lpConnection, lpConnection, dwSize );
  173.  
  174.         lpConnectionInfo->dwConnectionSize = dwSize;
  175.  
  176.         SendMessage( hWnd, CB_SETITEMDATA, iIndex, 
  177.                             ( LPARAM ) lpConnectionInfo );
  178.     }
  179.     else 
  180.     {
  181.         return FALSE;
  182.     }
  183.  
  184.     return( TRUE );
  185. }
  186.  
  187.  
  188. BOOL WINAPI EnumSession( LPDPSESSIONDESC2 lpDPGameDesc, LPDWORD lpdwTimeOut,
  189.                             DWORD dwFlags, LPVOID lpContext )
  190. {
  191.     LONG iIndex;
  192.     HWND hWnd = ( HWND ) lpContext;
  193.     LPGUID lpGuid;
  194.  
  195.     // First check and see if the enumeration timed out.  If so, we
  196.     // could reset it, but we'll just canel it instead.
  197.  
  198.     if( dwFlags & DPESC_TIMEDOUT )
  199.     {
  200.         return FALSE;
  201.     }
  202.  
  203.     iIndex = SendMessage( hWnd, LB_ADDSTRING, 0, 
  204.                             (LPARAM) lpDPGameDesc->lpszSessionName );
  205.  
  206.     // If it got added to the list box, create a copy of the GUID
  207.     // and store a pointer to it in the list box.
  208.  
  209.     if ( iIndex != LB_ERR )
  210.     {
  211.         lpGuid = ( LPGUID ) malloc( sizeof( GUID ) );
  212.         if ( !lpGuid ) return FALSE;
  213.  
  214.         *lpGuid = lpDPGameDesc->guidInstance;
  215.  
  216.         SendMessage( hWnd, LB_SETITEMDATA, iIndex, 
  217.                                 ( LPARAM ) lpGuid );
  218.     }
  219.  
  220.     return(TRUE);
  221. }
  222.  
  223.  
  224. LRESULT CALLBACK DlgProcEnumPlayers( HWND hWnd, UINT message, 
  225.                                         WPARAM wParam, LPARAM lParam )
  226. {
  227.     int iIndex;
  228.     LPGUID lpGuid;
  229.  
  230.     switch( message )
  231.     {
  232.         case WM_INITDIALOG:
  233.  
  234.             iIndex = SendDlgItemMessage( GetParent( hWnd ), IDC_SESSIONS, 
  235.                                     LB_GETCURSEL, 0, 0L );
  236.             lpGuid = ( LPGUID )SendDlgItemMessage( GetParent( hWnd ), 
  237.                         IDC_SESSIONS, LB_GETITEMDATA, iIndex, 0 );
  238.  
  239.             if FAILED( lpDP->EnumPlayers( lpGuid, 
  240.                             ( LPDPENUMPLAYERSCALLBACK2 )EnumPlayer,
  241.                             ( LPVOID )GetDlgItem( hWnd, IDC_PLAYERS ),
  242.                             DPENUMPLAYERS_SESSION ) )
  243.             {
  244.                 MessageBox( hWnd, "Error enumerating players.", 
  245.                                         "Error", MB_OK );
  246.                 EndDialog( hWnd, FALSE );
  247.             }
  248.  
  249.             return TRUE;
  250.  
  251.         case WM_COMMAND:         
  252.             switch( LOWORD( wParam ) )
  253.             {
  254.                 case IDOK:
  255.                 case IDCANCEL:
  256.                     EndDialog( hWnd, FALSE );
  257.                     return TRUE;
  258.             }
  259.  
  260.     }
  261.     return FALSE; 
  262. }
  263.  
  264.  
  265. BOOL CreateGamePlayer( void )
  266. {    
  267.     DPNAME dpPlayerName;
  268.     
  269.     ZeroMemory( &dpPlayerName, 
  270.                 sizeof( dpPlayerName ) );
  271.     dpPlayerName.dwSize = sizeof( DPNAME );
  272.     dpPlayerName.lpszShortNameA = g_szPlayerName;
  273.  
  274.     if FAILED( lpDP->CreatePlayer( &g_dpPlayerID, &dpPlayerName,
  275.                             hPlayerEvent, NULL, 0, 0 ) )
  276.     {
  277.         OutputDebugString( 
  278.             "CreateGamePlayer: Player create failed!\n" );
  279.         return FALSE;
  280.     }
  281.  
  282.     OutputDebugString( 
  283.         "CreateGamePlayer: Player created.\n" );
  284.     return TRUE;
  285. }
  286.  
  287.  
  288. BOOL CALLBACK DlgProcDPStart( HWND hWnd, UINT message, WPARAM wParam, 
  289.                            LPARAM lParam )
  290. {    
  291.     long                i;
  292.     HRESULT                hr;
  293.     LPDIRECTPLAYLOBBY    lpDPLobby    = NULL;
  294.     LPDIRECTPLAY2        lpDP2        = NULL;
  295.     LPVOID              lpHeap, lpConnection;
  296.     LPDPLCONNECTION        lpLConnection;
  297.     LPCONNECTIONINFO    lpConnectionInfo;
  298.     DWORD               dwSessions;
  299.     LPDELETEITEMSTRUCT  lpdis;
  300.     char                szSessionName[30];
  301.     LPGUID              lpGuid;
  302.  
  303.     DPCOMPOUNDADDRESSELEMENT    addressChunks[2];
  304.     DWORD                        dwChunkCount;
  305.     DWORD                        dwSize = 0;
  306.  
  307.     switch( message )
  308.     {
  309.         case WM_INITDIALOG:
  310.  
  311.             if FAILED( CoCreateInstance( CLSID_DirectPlay,
  312.                         NULL, CLSCTX_ALL, IID_IDirectPlay3A,
  313.                         ( LPVOID* ) &lpDP ) )
  314.             {
  315.                 MessageBox( hWnd, "Error creating DirectPlay object.", 
  316.                                 "Error", MB_OK );
  317.                 EndDialog( hWnd, -1 );
  318.             }
  319.  
  320.             if FAILED( DirectPlayLobbyCreate( NULL, &lpDPLobby, 
  321.                                                 NULL, NULL, 0 ) )
  322.             {
  323.                 MessageBox( hWnd, "Error creating DirectPlayLobby object.", 
  324.                                 "Error", MB_OK );
  325.                 EndDialog( hWnd, -1 );
  326.             }
  327.             // DirectPlayLobbyCreate gives us an IID_IDirectPlayLobby
  328.             // interface. Query for the newer *ANSI* interface.
  329.             else if FAILED( lpDPLobby->QueryInterface( 
  330.                         IID_IDirectPlayLobby2A, (LPVOID*) &lpDPLobby2 ) )
  331.             {
  332.                 MessageBox( hWnd, "Error getting Lobby interface.", 
  333.                             "Error", MB_OK );
  334.                 EndDialog( hWnd, -1 );
  335.             }
  336.  
  337.             // This version of the interface is no longer needed
  338.             lpDPLobby->Release();
  339.  
  340.             // Check for lobby launch
  341.  
  342.             hr = lpDPLobby2->GetConnectionSettings( 0, NULL, &dwSize );
  343.  
  344.             if ( hr != DPERR_NOTLOBBIED )
  345.  
  346.             {
  347.                 OutputDebugString("Attempting Lobby Launch...\n");
  348.  
  349.                 // We were lobbied. Get the connection settings.
  350.  
  351.                 lpLConnection = (LPDPLCONNECTION) malloc( dwSize );
  352.  
  353.                 lpDPLobby2->GetConnectionSettings( 0,
  354.                                             lpLConnection, &dwSize );
  355.  
  356.                 // Set the session up the way we want it.
  357.  
  358.                 lpLConnection->lpSessionDesc->dwFlags = DPSESSION_MIGRATEHOST |
  359.                                                         DPSESSION_KEEPALIVE;
  360.                 lpLConnection->lpSessionDesc->dwMaxPlayers = 4;
  361.                 lpDPLobby2->SetConnectionSettings( 0, 0, lpLConnection );
  362.                 
  363.                 // Connect to the session.
  364.                 lpDPLobby2->Connect( 0, &lpDP2, NULL );
  365.  
  366.                 lpDP2->QueryInterface( IID_IDirectPlay3A, (LPVOID*)&lpDP );
  367.  
  368.                 lpDP2->Release();
  369.  
  370.                 EndDialog( hWnd, 0 );
  371.             }
  372.  
  373.             // Fill the connections drop down list box
  374.             SendDlgItemMessage( hWnd, IDC_CONNECTIONS,
  375.                                 CB_ADDSTRING, 0, 
  376.                                 (LPARAM) "<<Select a Connection>>" );
  377.  
  378.             if FAILED( lpDP->EnumConnections( NULL, 
  379.                         ( LPDPENUMCONNECTIONSCALLBACK )EnumConnection,
  380.                         ( LPVOID )GetDlgItem( hWnd, IDC_CONNECTIONS ),
  381.                         0 ) )
  382.             {
  383.                 MessageBox( hWnd, "Couldn't enumerate connections.",
  384.                                 "Error", MB_OK );
  385.                 EndDialog( hWnd, -1 );
  386.             }
  387.             else
  388.             {
  389.                 SendDlgItemMessage( hWnd, IDC_CONNECTIONS, 
  390.                     CB_SETCURSEL, 0, 0L );
  391.             }
  392.  
  393.             // Start a timer for async session list
  394.             SetTimer( hWnd, TIMER_ID, TIMER_RATE, NULL );
  395.  
  396.             return TRUE;
  397.  
  398.         case WM_DELETEITEM:
  399.             // Delete the memory allocated when the list and combo
  400.             // boxes are filled.
  401.  
  402.             lpdis = ( LPDELETEITEMSTRUCT ) lParam;
  403.  
  404.             if ( wParam == IDC_CONNECTIONS )
  405.             {
  406.                 lpConnectionInfo = ( LPCONNECTIONINFO )lpdis->itemData;
  407.                 if ( lpConnectionInfo )
  408.                 {
  409.                     if ( lpConnectionInfo->lpConnection )
  410.                         free( lpConnectionInfo->lpConnection );
  411.                     free( lpConnectionInfo );
  412.                 }
  413.             }
  414.             else
  415.             {
  416.                 lpHeap = ( LPVOID )lpdis->itemData;
  417.                 if ( lpHeap ) 
  418.                     free( lpHeap );
  419.             }
  420.  
  421.             return TRUE;
  422.  
  423.         case WM_COMMAND:         
  424.             switch( LOWORD( wParam ) )
  425.             {
  426.                 case IDC_CONNECTIONS:
  427.                     switch (HIWORD(wParam))
  428.                     {
  429.                         case CBN_SELCHANGE:
  430.                             // Release the existing DP object so we can 
  431.                             // reinitialize it with the selected connection.
  432.  
  433.                             if ( lpDP ) lpDP->Release();
  434.  
  435.                             if FAILED( CoCreateInstance( CLSID_DirectPlay,
  436.                                 NULL, CLSCTX_ALL, IID_IDirectPlay3A,
  437.                                 ( LPVOID* ) &lpDP) )
  438.                             {
  439.                                 MessageBox( hWnd, 
  440.                                     "Error creating DirectPlay object.",
  441.                                     "Error", MB_OK );
  442.                                 return TRUE;
  443.                             }
  444.                             
  445.                             // Get the currently selected connection from 
  446.                             // the list box.
  447.                             i = SendDlgItemMessage( hWnd, IDC_CONNECTIONS, 
  448.                                                         CB_GETCURSEL,
  449.                                                         0, 0L );
  450.                             lpConnectionInfo = (LPCONNECTIONINFO)
  451.                                                         SendDlgItemMessage(
  452.                                                         hWnd, IDC_CONNECTIONS, 
  453.                                                         CB_GETITEMDATA,
  454.                                                         i, 0 );
  455.                             
  456.                             lpConnection = lpConnectionInfo->lpConnection;
  457.  
  458.                             // If the connection uses the TCP/IP service 
  459.                             // provider, fill in chunks for the provider
  460.                             // and TCP/IP address.
  461.                             if ( IsEqualGUID( lpConnectionInfo->guidSP, 
  462.                                                         DPSPGUID_TCPIP ) )
  463.                             {
  464.                                 dwChunkCount = 0;
  465.  
  466.                                 addressChunks[ dwChunkCount ].guidDataType = 
  467.                                                         DPAID_ServiceProvider;
  468.                                 addressChunks[ dwChunkCount ].dwDataSize = 
  469.                                                             sizeof(GUID);
  470.                                 addressChunks[ dwChunkCount ].lpData = 
  471.                                                     (LPVOID) &DPSPGUID_TCPIP;
  472.                                 dwChunkCount++;
  473.  
  474.                                 // An empty address will trigger a
  475.                                 // local enumeration.
  476.                                 addressChunks[dwChunkCount].guidDataType = 
  477.                                                                     DPAID_INet;
  478.                                 addressChunks[dwChunkCount].dwDataSize = 1;
  479.                                 addressChunks[dwChunkCount].lpData = "";
  480.                                 dwChunkCount++;
  481.  
  482.                                 // Find out how much space we'll need for
  483.                                 // the connection data and allocate.
  484.                                 lpDPLobby2->CreateCompoundAddress(
  485.                                                     addressChunks, 
  486.                                                     dwChunkCount, 
  487.                                                     NULL, &dwSize );
  488.  
  489.                                 lpConnection = malloc( dwSize );
  490.  
  491.                                 // Create the connection buffer.
  492.                                 if FAILED( lpDPLobby2->CreateCompoundAddress(
  493.                                                         addressChunks, 
  494.                                                         dwChunkCount,
  495.                                                         lpConnection, 
  496.                                                         &dwSize ) )
  497.                                 {
  498.                                     OutputDebugString(
  499.                                         "Couldn't create compound address.\n");
  500.                                 }
  501.  
  502.                             }
  503.  
  504.                             if FAILED( lpDP->InitializeConnection( 
  505.                                                         lpConnection, 0 ) )
  506.                             {
  507.                                 MessageBox( hWnd, 
  508.                                     "Error initializing DirectPlay object.",
  509.                                     "Error", MB_OK );
  510.                                 EnableWindow( GetDlgItem( hWnd, IDCREATE ),
  511.                                                 FALSE );
  512.                                 EnableWindow( GetDlgItem( hWnd, IDPLAYERS ),
  513.                                                 FALSE );
  514.                                 EnableWindow( GetDlgItem( hWnd, IDJOIN ),
  515.                                                 FALSE );
  516.                             }
  517.                             else
  518.                             {
  519.                                 EnableWindow( GetDlgItem( hWnd, IDCREATE ),
  520.                                                 TRUE );
  521.                                 bUserCancel = FALSE;
  522.                             }
  523.                             return TRUE;
  524.                     }
  525.                     return TRUE;
  526.  
  527.  
  528.                 case IDPLAYERS:
  529.                     DialogBox( (HINSTANCE)g_hInstance, MAKEINTRESOURCE( IDD_PLAYERS ), hWnd,
  530.                                 ( DLGPROC )DlgProcEnumPlayers );
  531.                     return TRUE;
  532.  
  533.                 case IDJOIN:
  534.                     OutputDebugString("*********Joining!\n");
  535.                     i = SendDlgItemMessage( hWnd, IDC_SESSIONS, 
  536.                                 LB_GETCURSEL, 0, 0L );
  537.                     lpGuid = ( LPGUID )SendDlgItemMessage( hWnd, 
  538.                                 IDC_SESSIONS, LB_GETITEMDATA, i, 0 );
  539.  
  540.                     ZeroMemory( &dpDesc, sizeof( dpDesc ) );
  541.                     dpDesc.dwSize = sizeof( dpDesc );
  542.                     dpDesc.guidInstance = *lpGuid;
  543.                     dpDesc.guidApplication = ZCAR_GUID;
  544.  
  545.                     if FAILED( lpDP->Open( &dpDesc, DPOPEN_JOIN ) )
  546.                     {         
  547.                         MessageBox( hWnd, "Could not join session.", 
  548.                                         "Error", MB_OK );
  549.                         EndDialog( hWnd, -1 );
  550.                     }
  551.                     else
  552.                     {
  553.                         EndDialog( hWnd, 0 );
  554.                     }
  555.                     return TRUE;
  556.  
  557.                 case IDCREATE:
  558.                     // Create the session with the supplied parameters
  559.                     GetDlgItemText( hWnd, IDC_SESSIONNAME, 
  560.                         szSessionName, 30 );
  561.  
  562.                     ZeroMemory( &dpDesc, sizeof( dpDesc ) );
  563.                     dpDesc.dwSize = sizeof( dpDesc );
  564.                     dpDesc.guidApplication = ZCAR_GUID;
  565.                     dpDesc.dwFlags = DPSESSION_MIGRATEHOST |
  566.                                         DPSESSION_KEEPALIVE;
  567.                     dpDesc.dwMaxPlayers = 4;
  568.                     dpDesc.lpszSessionNameA = szSessionName;
  569.  
  570.                     if FAILED( lpDP->Open( &dpDesc, DPOPEN_CREATE ) )
  571.                     {         
  572.                         MessageBox( hWnd, "Could not create session.", 
  573.                                         "Error", MB_OK );
  574.                         EndDialog( hWnd, -1 );
  575.                     }
  576.                     else
  577.                     {
  578.                         EndDialog( hWnd, 0 );
  579.                     }
  580.                     return TRUE;
  581.  
  582.                 case IDCANCEL:
  583.                     EndDialog( hWnd, -2 );
  584.                     return TRUE;
  585.             }
  586.             break;
  587.  
  588.         case WM_TIMER:
  589.             if ( bEnumerating || bUserCancel ) return TRUE;
  590.  
  591.             // Display the current session list if
  592.             // there is a valid DPlay object
  593.  
  594.             SendDlgItemMessage(hWnd, IDC_SESSIONS, 
  595.                                 LB_RESETCONTENT, 0, 0L);
  596.  
  597.             ZeroMemory( &dpDesc, sizeof( dpDesc ) );
  598.             dpDesc.dwSize = sizeof( dpDesc );
  599.             dpDesc.guidApplication = ZCAR_GUID;
  600.  
  601.             dwSessions = DPENUMSESSIONS_AVAILABLE | 
  602.                             DPENUMSESSIONS_ASYNC;
  603.  
  604.             bEnumerating = TRUE;
  605.  
  606.             // Start the enumeration
  607.             hr = lpDP->EnumSessions( &dpDesc, 0, 
  608.                     ( LPDPENUMSESSIONSCALLBACK2 )EnumSession, 
  609.                     ( LPVOID ) GetDlgItem( hWnd, IDC_SESSIONS ), 
  610.                     dwSessions );
  611.  
  612.             if ( hr == DPERR_USERCANCEL ) {
  613.                 bUserCancel = TRUE;
  614.             }
  615.  
  616.             bEnumerating = FALSE;
  617.  
  618.             // Adjust the user interface accordingly if there
  619.             // are sessions available
  620.             if ( SendDlgItemMessage( hWnd, IDC_SESSIONS, 
  621.                                         LB_GETCOUNT, 0, 0 ) > 0 )
  622.             {
  623.                 EnableWindow( GetDlgItem( hWnd, IDPLAYERS ),
  624.                     TRUE );
  625.                 EnableWindow( GetDlgItem( hWnd, IDJOIN ),
  626.                     TRUE );
  627.                 SendDlgItemMessage( hWnd, IDC_SESSIONS,
  628.                                         LB_SETCURSEL, 0, 0 );
  629.             }
  630.             else
  631.             {
  632.                 EnableWindow( GetDlgItem( hWnd, IDPLAYERS ),
  633.                     FALSE );
  634.                 EnableWindow( GetDlgItem( hWnd, IDJOIN ),
  635.                     FALSE );
  636.             }
  637.             return TRUE;
  638.                     
  639.         case WM_DESTROY:
  640.             // Save the player name for later
  641.             GetDlgItemText( hWnd, IDC_PLAYER,
  642.                             g_szPlayerName, 30 );
  643.  
  644.             KillTimer( hWnd, TIMER_ID );
  645.             break;
  646.  
  647.     }
  648.     return FALSE; 
  649. }
  650.  
  651.  
  652.  
  653. void EvaluateGameMessage( LPGENERICMSG lpGeneric, DPID pidFrom )
  654. {   
  655.  
  656.     switch( lpGeneric->byType )
  657.     {
  658.         case MSG_HOST:
  659.             // If we're getting this message, we must be a new
  660.             // player. Get the slot from the slot number, fill it.
  661.             OutputDebugString("Processing welcome message.\n");
  662.             LPHOSTMSG       lpHost;
  663.             lpHost = (LPHOSTMSG) lpGeneric;
  664.             
  665.             break;
  666.  
  667.         case MSG_FIRE:
  668.             OutputDebugString("Getting fire!\n");
  669.             LPFIREMSG    lpFire;
  670.             lpFire = (LPFIREMSG) lpGeneric;
  671.  
  672.             receive_count = lpFire->sddata;
  673.  
  674.             break;
  675.  
  676.         case MSG_SYNC:
  677.             LPSYNCMSG    lpSync;
  678.             lpSync = (LPSYNCMSG) lpGeneric;
  679.  
  680.             
  681.             break;
  682.  
  683.         case MSG_CONTROL:
  684.             LPCONTROLMSG    lpControl;
  685.             lpControl = (LPCONTROLMSG) lpGeneric;
  686.             break;
  687.     }  
  688. }
  689.  
  690.  
  691.  
  692. int ReceiveFireMessage()
  693. {
  694.     return(receive_count);
  695. }
  696.  
  697.  
  698.  
  699.  
  700. void EvaluateSystemMessage( DPMSG_GENERIC *pGeneric, HWND hWnd )
  701. {    
  702.  
  703. //    int ass;
  704.     switch( pGeneric->dwType )
  705.     {
  706.         // The message comes to us cast as DPMSG_GENERIC.  We'll examine
  707.         // dwType to determine the type of message, then cast to the new
  708.         // type and evaluate the rest of the message.
  709.  
  710.         case DPSYS_CREATEPLAYERORGROUP:
  711.         {
  712.             DPMSG_CREATEPLAYERORGROUP *pMsg;
  713.             pMsg = (DPMSG_CREATEPLAYERORGROUP *) pGeneric;
  714.  
  715.             OutputDebugString("A player has joined.\n");
  716.  
  717.             if ( g_bHost )
  718.             {
  719.             //    MsgHost.bySlot = FindPlayerSlot();
  720.                 SendGameMessage( (LPGENERICMSG)&MsgHost, pMsg->dpId );
  721.                 OutputDebugString( "Sending welcome message.\n" );
  722.             }
  723.  
  724.             break;
  725.         }
  726.  
  727.         case DPSYS_DESTROYPLAYERORGROUP:
  728.         {
  729.             DPMSG_DESTROYPLAYERORGROUP *pMsg;
  730.             pMsg = (DPMSG_DESTROYPLAYERORGROUP *) pGeneric;
  731.  
  732.             OutputDebugString("A player has left.\n");
  733.  
  734.             // Remove the player from the game
  735.         }
  736.  
  737.         case DPSYS_HOST:
  738.         {
  739.             g_bHost = TRUE;
  740.             OutputDebugString( "This machine is now the session host.\n" );
  741.             break;
  742.         }       
  743.     }      
  744. }
  745.  
  746.  
  747. void ReceiveMessages( HWND hWnd )
  748. {
  749.     DPID            fromID;
  750.     DPID            toID;
  751.     DWORD           nBytes;
  752.     DPMSG_GENERIC   *pGeneric;
  753.     LPGENERICMSG    pGameMsg;
  754.     HRESULT         dprval;
  755.  
  756.  
  757.     // Don't let Receive work use the global value directly,
  758.     // as it changes it.
  759.     nBytes = dwReceiveBufferSize;
  760.  
  761.     while( TRUE )
  762.  
  763.     {   
  764.         dprval = lpDP->Receive( &fromID, &toID,
  765.                             DPRECEIVE_ALL, lpReceiveBuffer, &nBytes);
  766.  
  767.  
  768.         if ( dprval == DPERR_BUFFERTOOSMALL )
  769.         // The recieve buffer size must be adjusted.
  770.         {
  771.             if ( lpReceiveBuffer == NULL)
  772.             {
  773.                 // We haven't allocated any buffer yet -- do it.
  774.                 lpReceiveBuffer = malloc( nBytes );
  775.                 if ( lpReceiveBuffer == NULL ) {
  776.                     OutputDebugString( "Couldn't allocate memory.\n" );
  777.                     return;
  778.                 }
  779.             }
  780.             else
  781.             {
  782.                 // The buffer's been allocated, but it's too small so
  783.                 // it must be enlarged.
  784.                 free( lpReceiveBuffer );
  785.                 lpReceiveBuffer = malloc( nBytes );
  786.                 if ( lpReceiveBuffer == NULL ) {
  787.                     OutputDebugString( "Couldn't allocate memory.\n" );
  788.                     return;
  789.                 }
  790.             }
  791.             // Update our global to the new buffer size.
  792.             dwReceiveBufferSize = nBytes;
  793.         }
  794.         else if ( dprval == DP_OK )
  795.         // A message was successfully retrieved.
  796.         {    
  797.             if ( fromID == DPID_SYSMSG )
  798.             {
  799.                 pGeneric = (DPMSG_GENERIC *) lpReceiveBuffer;
  800.                 OutputDebugString( "Processing system message.\n" );
  801.                 EvaluateSystemMessage ( pGeneric, hWnd );
  802.             }
  803.             else
  804.             {
  805.                 pGameMsg = (LPGENERICMSG) lpReceiveBuffer;
  806.                 OutputDebugString("Processing game message.\n");
  807.                 EvaluateGameMessage( pGameMsg, fromID );
  808.             }
  809.         }
  810.         else
  811.         {
  812.             return;
  813.         }
  814.     }
  815. }
  816.  
  817.  
  818. DWORD WINAPI ReceiveThread( LPVOID lpParameter )
  819. {
  820.     HWND        hWnd = (HWND) lpParameter;
  821.     HANDLE      eventHandles[2];
  822.     eventHandles[0] = hPlayerEvent;
  823.     eventHandles[1] = hKillEvent;
  824.  
  825.     // Wait for either the player or kill event to fire.  If it
  826.     // is the player event (WAIT_OBJECT_0), process the messages
  827.     // and wait again.  If it's the kill event, shut down the
  828.     // thread and exit
  829.  
  830.     while (WaitForMultipleObjects( 2, eventHandles, FALSE,
  831.                 INFINITE) == WAIT_OBJECT_0 )
  832.     {
  833.         OutputDebugString( "Thread awakened.\n" );
  834.         ReceiveMessages( hWnd );
  835.     }
  836.  
  837.     ExitThread( 0 );
  838.  
  839.     return ( 0 );
  840. }
  841.  
  842.  
  843. int StartDPSession( void )
  844. {
  845.     int rc;
  846.  
  847.     // Call the dialog for establishing a connection
  848.     rc = DialogBox((HINSTANCE) g_hInstance, MAKEINTRESOURCE(IDD_CONNECT), 
  849.                             g_hwnd, (DLGPROC)DlgProcDPStart );
  850.  
  851.     if ( !rc )
  852.     {
  853.         InitMessageBuffers();
  854.  
  855.         // Create an event that will be used to signal when
  856.         // the player has messages
  857.         hPlayerEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  858.  
  859.         hKillEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  860.  
  861.         hReceiveThread = CreateThread(NULL,
  862.                                    0,           
  863.                                    ReceiveThread,
  864.                                    g_hwnd,
  865.                                    0,           
  866.                                    &idReceiveThread);
  867.  
  868.          // Get the caps for the session
  869.         ZeroMemory( &dpCaps, sizeof( dpCaps ) );
  870.         dpCaps.dwSize = sizeof( dpCaps );
  871.         lpDP->GetCaps( &dpCaps, 0 );
  872.  
  873.         // Are we the session host?
  874.         if ( dpCaps.dwFlags & DPCAPS_ISHOST  )
  875.         {
  876.             g_bHost = TRUE;
  877.             OutputDebugString( "We are the session host.\n" );
  878.         }
  879.     }
  880.     return rc;
  881. }
  882.  
  883.  
  884. BOOL ShutDownDPSession( void )
  885. {
  886.     // Destroy the local player
  887.     if ( g_dpPlayerID )
  888.     {
  889.         lpDP->DestroyPlayer( g_dpPlayerID );
  890.         g_dpPlayerID = 0;
  891.     }
  892.  
  893.     // Shut down the recieve thread
  894.     if ( hReceiveThread )
  895.     {
  896.         // Signal event to kill receive thread
  897.         SetEvent( hKillEvent );
  898.  
  899.         // Wait for the thread to shut down
  900.         WaitForSingleObject( hReceiveThread, INFINITE );
  901.  
  902.         CloseHandle( hReceiveThread); 
  903.         hReceiveThread = NULL;
  904.     }
  905.  
  906.     // Close the other events
  907.     if ( hKillEvent ) 
  908.     {
  909.         CloseHandle( hKillEvent );
  910.         hKillEvent = NULL;
  911.     }
  912.     if ( hPlayerEvent )
  913.     {
  914.         CloseHandle( hPlayerEvent );
  915.         hPlayerEvent = NULL;
  916.     }
  917.  
  918.     // Free the receive buffer.
  919.     if ( lpReceiveBuffer )
  920.     {
  921.         free( lpReceiveBuffer );
  922.         lpReceiveBuffer = NULL;
  923.     }
  924.  
  925.     // Release the DirectPlay object and the Lobby object
  926.     if ( lpDP )
  927.     {
  928.         OutputDebugString( "Releasing the DP object.\n" );
  929.         lpDP->Release();
  930.         lpDP = NULL;
  931.     }
  932.     if ( lpDPLobby2 )
  933.     {
  934.         OutputDebugString( "Releasing the lobby object.\n" );
  935.         lpDPLobby2->Release();
  936.         lpDPLobby2 = NULL;
  937.     }
  938.     return TRUE;
  939. }
  940.  
  941.  
  942. void SendSyncMessage()
  943.  
  944. {
  945.  
  946. //MsgSync.x = vehicle->x;
  947.  
  948. SendGameMessage( (LPGENERICMSG)&MsgSync, DPID_ALLPLAYERS );
  949.  
  950. }
  951.  
  952.  
  953. void SendFireMessage(int send_me)
  954. {
  955.  
  956.     MsgFire.sddata = send_me;
  957.  
  958.     SendGameMessage( (LPGENERICMSG)&MsgFire, DPID_ALLPLAYERS );
  959. }
  960.  
  961.  
  962. void SendControlMessage( BYTE byControl )
  963. {
  964.  
  965.     MsgControl.byState = byControl;
  966.     SendGameMessage( (LPGENERICMSG)&MsgControl, DPID_ALLPLAYERS );
  967. }
  968.  
  969.  
  970. void SendGameMessage( LPGENERICMSG lpMsg, DPID idTo )
  971. {
  972.     int             nBytes;
  973.     DWORD            dwFlags = 0;
  974.  
  975.     switch( lpMsg->byType )
  976.     {
  977.         case MSG_HOST:
  978.             nBytes = sizeof( HOSTMSG );
  979.             dwFlags = DPSEND_GUARANTEED;
  980.             break;
  981.  
  982.         case MSG_SYNC:
  983.             nBytes = sizeof( SYNCMSG );
  984.             break;
  985.  
  986.         case MSG_FIRE:
  987.             nBytes = sizeof( FIREMSG );
  988.             dwFlags = DPSEND_GUARANTEED;
  989.             break;
  990.  
  991.         case MSG_CONTROL:
  992.             nBytes = sizeof( CONTROLMSG );
  993.             break;
  994.  
  995.         default:
  996.             return;
  997.     }
  998.  
  999.     // Send the message buffer
  1000.     lpDP->Send( g_dpPlayerID, idTo, dwFlags, (LPVOID)lpMsg, nBytes);    
  1001. }
  1002.  
  1003.  
  1004.  
  1005.  
  1006. ///new aggregate stuff, added by SIM(4-08-99)
  1007.  
  1008. BOOL InitializeDirectPlay( HANDLE hInstance)
  1009. {    
  1010.     CoInitialize( NULL );    
  1011.     int rc;
  1012.     g_hInstance = hInstance;
  1013.  
  1014.     // Attempt to initialize DirectPlay
  1015.     rc = StartDPSession();
  1016.  
  1017.     switch ( rc )
  1018.     {
  1019.         case -1:
  1020.             // Something failed when attempting DirectPlay init
  1021.             MessageBox( NULL, "DirectPlay Init FAILED try including the rc file", "ERROR", MB_OK );
  1022.             // Fall through
  1023.         case -2:
  1024.             // The user pressed the cancel button.
  1025.             OutputDebugString( "The user cancelled DPlay.\n" );
  1026.             return FALSE;
  1027.     }
  1028.  
  1029.     CreateGamePlayer();         
  1030.     return TRUE;
  1031. }
  1032.  
  1033.  
  1034. void UninitializeDirectPlay()
  1035. {    
  1036.     CoUninitialize();
  1037.     ShutDownDPSession();
  1038. //MessageBox(NULL, "uninit", "uninit", MB_OK);
  1039. }
  1040.  
  1041.  
  1042.